# -*- coding: utf-8 -*-
"""
DTM验证工具 - 文件管理模块
负责文件路径管理、目录操作和文件验证
"""

import os
import shutil
from pathlib import Path
from typing import List, Optional, Dict, Tuple
from datetime import datetime
from config_manager import Constants


class FilePathManager:
    """文件路径管理器"""

    def __init__(self, project_root: Optional[str] = None):
        self.project_root = project_root or os.path.dirname(os.path.abspath(__file__))
        self.input_dir = os.path.join(self.project_root, "input")
        self.output_dir = os.path.join(self.project_root, "output")
        self.constants = Constants()

        # 创建必要的目录
        self._ensure_directories_exist()

    def _ensure_directories_exist(self):
        """确保必要的目录存在"""
        directories = [self.input_dir, self.output_dir]
        for directory in directories:
            os.makedirs(directory, exist_ok=True)

    def get_input_directory(self) -> str:
        """获取输入目录路径"""
        return self.input_dir

    def get_output_directory(self) -> str:
        """获取输出目录路径"""
        return self.output_dir

    def set_input_directory(self, path: str) -> None:
        """设置输入目录路径"""
        if os.path.exists(path):
            self.input_dir = path
        else:
            raise FileNotFoundError(f"输入目录不存在: {path}")

    def set_output_directory(self, path: str) -> None:
        """设置输出目录路径"""
        self.output_dir = path
        os.makedirs(self.output_dir, exist_ok=True)

    def generate_output_filename(
        self, input_file_path: str, suffix: str = "", extension: str = ""
    ) -> str:
        """
        根据输入文件路径生成输出文件名

        Args:
            input_file_path: 输入文件路径
            suffix: 文件名后缀
            extension: 文件扩展名

        Returns:
            str: 完整的输出文件路径
        """
        base_name = os.path.splitext(os.path.basename(input_file_path))[0]

        if suffix:
            output_filename = f"{base_name}_{suffix}"
        else:
            output_filename = base_name

        if extension:
            if not extension.startswith("."):
                extension = f".{extension}"
            output_filename += extension

        return os.path.join(self.output_dir, output_filename)

    def get_relative_path(self, file_path: str) -> str:
        """获取相对于项目根目录的相对路径"""
        try:
            return os.path.relpath(file_path, self.project_root)
        except ValueError:
            # 如果路径在不同的驱动器上，返回绝对路径
            return file_path

    def cleanup_output_directory(self, pattern: Optional[str] = None) -> int:
        """
        清理输出目录

        Args:
            pattern: 文件名模式（可选），如果提供，只删除匹配的文件

        Returns:
            int: 删除的文件数量
        """
        deleted_count = 0

        if not os.path.exists(self.output_dir):
            return deleted_count

        for filename in os.listdir(self.output_dir):
            file_path = os.path.join(self.output_dir, filename)

            if os.path.isfile(file_path):
                if pattern is None or pattern in filename:
                    try:
                        os.remove(file_path)
                        deleted_count += 1
                    except OSError:
                        pass  # 忽略删除失败的文件

        return deleted_count


class FileValidator:
    """文件验证器"""

    def __init__(self):
        self.constants = Constants()

    def validate_excel_file(self, file_path: str) -> Dict[str, any]:
        """
        验证Excel文件的基本属性

        Args:
            file_path: 文件路径

        Returns:
            Dict[str, any]: 验证结果
        """
        result = {
            "is_valid": False,
            "exists": False,
            "readable": False,
            "correct_extension": False,
            "file_size": 0,
            "error_message": None,
        }

        try:
            # 检查文件是否存在
            if not os.path.exists(file_path):
                result["error_message"] = "文件不存在"
                return result

            result["exists"] = True

            # 检查文件扩展名
            _, ext = os.path.splitext(file_path.lower())
            if ext not in self.constants.EXCEL_FILE_EXTENSIONS:
                result["error_message"] = f"不支持的文件格式: {ext}"
                return result

            result["correct_extension"] = True

            # 检查文件大小
            result["file_size"] = os.path.getsize(file_path)
            if result["file_size"] == 0:
                result["error_message"] = "文件为空"
                return result

            # 检查文件是否可读
            try:
                with open(file_path, "rb") as f:
                    f.read(1)  # 尝试读取一个字节
                result["readable"] = True
            except PermissionError:
                result["error_message"] = "文件无法读取（权限不足）"
                return result
            except Exception as e:
                result["error_message"] = f"文件读取错误: {str(e)}"
                return result

            result["is_valid"] = True

        except Exception as e:
            result["error_message"] = f"验证过程中发生错误: {str(e)}"

        return result

    def batch_validate_files(self, file_paths: List[str]) -> Dict[str, Dict[str, any]]:
        """
        批量验证文件

        Args:
            file_paths: 文件路径列表

        Returns:
            Dict[str, Dict[str, any]]: 每个文件的验证结果
        """
        results = {}

        for file_path in file_paths:
            results[file_path] = self.validate_excel_file(file_path)

        return results

    def get_validation_summary(
        self, validation_results: Dict[str, Dict[str, any]]
    ) -> Dict[str, any]:
        """
        获取批量验证的汇总信息

        Args:
            validation_results: 批量验证结果

        Returns:
            Dict[str, any]: 汇总信息
        """
        total_files = len(validation_results)
        valid_files = sum(
            1 for result in validation_results.values() if result["is_valid"]
        )
        invalid_files = total_files - valid_files

        return {
            "total_files": total_files,
            "valid_files": valid_files,
            "invalid_files": invalid_files,
            "validation_rate": (
                (valid_files / total_files * 100) if total_files > 0 else 0
            ),
            "invalid_file_list": [
                path
                for path, result in validation_results.items()
                if not result["is_valid"]
            ],
        }


class DirectoryScanner:
    """目录扫描器"""

    def __init__(self):
        self.constants = Constants()

    def scan_directory_for_excel_files(
        self, directory_path: str, recursive: bool = False
    ) -> List[str]:
        """
        扫描目录查找Excel文件

        Args:
            directory_path: 目录路径
            recursive: 是否递归扫描子目录

        Returns:
            List[str]: Excel文件路径列表
        """
        excel_files = []

        if not os.path.exists(directory_path):
            return excel_files

        try:
            if recursive:
                # 递归扫描
                for root, dirs, files in os.walk(directory_path):
                    for file in files:
                        if self._is_excel_file(file):
                            full_path = os.path.join(root, file)
                            excel_files.append(full_path)
            else:
                # 只扫描当前目录
                for file in os.listdir(directory_path):
                    full_path = os.path.join(directory_path, file)
                    if os.path.isfile(full_path) and self._is_excel_file(file):
                        excel_files.append(full_path)

        except PermissionError:
            pass  # 忽略权限错误

        return sorted(excel_files)  # 返回排序后的列表

    def _is_excel_file(self, filename: str) -> bool:
        """检查文件是否为Excel文件"""
        _, ext = os.path.splitext(filename.lower())
        return ext in self.constants.EXCEL_FILE_EXTENSIONS

    def get_directory_info(self, directory_path: str) -> Dict[str, any]:
        """
        获取目录信息

        Args:
            directory_path: 目录路径

        Returns:
            Dict[str, any]: 目录信息
        """
        info = {
            "exists": False,
            "readable": False,
            "total_files": 0,
            "excel_files": 0,
            "subdirectories": 0,
            "total_size": 0,
        }

        if not os.path.exists(directory_path):
            return info

        info["exists"] = True

        try:
            files = os.listdir(directory_path)
            info["readable"] = True

            for item in files:
                item_path = os.path.join(directory_path, item)

                if os.path.isfile(item_path):
                    info["total_files"] += 1
                    info["total_size"] += os.path.getsize(item_path)

                    if self._is_excel_file(item):
                        info["excel_files"] += 1

                elif os.path.isdir(item_path):
                    info["subdirectories"] += 1

        except PermissionError:
            pass  # 权限不足时保持默认值

        return info


class FileOperationManager:
    """文件操作管理器"""

    def __init__(self, output_dir: str):
        self.output_dir = output_dir
        self.file_validator = FileValidator()
        os.makedirs(output_dir, exist_ok=True)

    def backup_existing_file(self, file_path: str) -> Optional[str]:
        """
        备份已存在的文件

        Args:
            file_path: 文件路径

        Returns:
            Optional[str]: 备份文件路径，如果不需要备份则返回None
        """
        if not os.path.exists(file_path):
            return None

        # 生成备份文件名
        base_name, ext = os.path.splitext(file_path)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_path = f"{base_name}_backup_{timestamp}{ext}"

        try:
            shutil.copy2(file_path, backup_path)
            return backup_path
        except Exception:
            return None

    def safe_file_write(
        self, file_path: str, content: any, backup: bool = True
    ) -> bool:
        """
        安全地写入文件（包括备份机制）

        Args:
            file_path: 文件路径
            content: 文件内容
            backup: 是否创建备份

        Returns:
            bool: 写入是否成功
        """
        try:
            # 备份现有文件
            if backup and os.path.exists(file_path):
                self.backup_existing_file(file_path)

            # 写入新内容
            if isinstance(content, str):
                with open(file_path, "w", encoding="utf-8") as f:
                    f.write(content)
            else:
                with open(file_path, "wb") as f:
                    f.write(content)

            return True

        except Exception:
            return False

    def organize_output_files(self) -> Dict[str, List[str]]:
        """
        整理输出目录中的文件

        Returns:
            Dict[str, List[str]]: 按文件类型分组的文件列表
        """
        organized_files = {"images": [], "reports": [], "logs": [], "others": []}

        if not os.path.exists(self.output_dir):
            return organized_files

        for filename in os.listdir(self.output_dir):
            file_path = os.path.join(self.output_dir, filename)

            if os.path.isfile(file_path):
                _, ext = os.path.splitext(filename.lower())

                if ext in [".png", ".jpg", ".jpeg", ".svg"]:
                    organized_files["images"].append(file_path)
                elif ext in [".xlsx", ".xls", ".csv"]:
                    organized_files["reports"].append(file_path)
                elif ext in [".txt", ".log"]:
                    organized_files["logs"].append(file_path)
                else:
                    organized_files["others"].append(file_path)

        # 对每个类别的文件进行排序
        for category in organized_files:
            organized_files[category].sort()

        return organized_files

    def get_output_summary(self) -> Dict[str, any]:
        """
        获取输出目录的汇总信息

        Returns:
            Dict[str, any]: 输出汇总信息
        """
        organized_files = self.organize_output_files()

        total_files = sum(len(files) for files in organized_files.values())
        total_size = 0

        # 计算总大小
        for file_list in organized_files.values():
            for file_path in file_list:
                try:
                    total_size += os.path.getsize(file_path)
                except OSError:
                    pass

        return {
            "total_files": total_files,
            "total_size_mb": total_size / (1024 * 1024),
            "files_by_type": {
                category: len(files) for category, files in organized_files.items()
            },
            "organized_files": organized_files,
            "output_directory": self.output_dir,
        }
